/*
 * handle_level.cpp
 *
 *  Created on: Oct 19, 2013
 *      Author: killerg
 */



#include "../../server_deps.h"
#include "../../server.h"
#include "../../client_session.h"
#include "../../server_console.h"

#include "share/net_s.h"
#include "share/msg.h"
#include "share/util.h"
#include "share/clock.h"


#include "../proto_mgr.h"
#include "../player_data.h"
#include "../combat.h"
#include "../occupation_mgr.h"
#include "../player_mgr.h"
#include "../game_cfg.h"

void handle_cventurecombat(client_session_t* sess, cs::CMsg* msg) {
    auto player = sess->player;
    if (NULL == sess->player)
        return;

    int32_t cur_levelid = player->att(Pl4s_VentCurLevel);
    int32_t levelid = msg->venturecombat().levelid();

    const tagProtoLevel* level_proto = MAProto(Level, levelid);
    if (NULL == level_proto) {
        sess->send_notify("无此关卡 levelproto:%d", levelid);
        return;
    }

    if (level_proto->taskpage >= 0 && player->att(Pl4s_TaskPage) < level_proto->taskpage) {
        sess->send_notify("开启完成任务篇章 %d", level_proto->taskpage);
        return;
    }

    int power = player->att(Pl4s_Power);
    if (power <= 0) {
        sess->send_notify("体力不足");
        return;
    }

    player->att(Pl4s_Power, power-1);

    CREATE_CS_SMSG(SCombat, combat);
    g_combatcookie(player.get(), NULL, 1);
    bool win = g_combat(player.get(), levelid, combat->mutable_combat());
    combat->set_levelid(levelid);
    sess->send_msg(___msg);

    if (win) {
        if (levelid == cur_levelid)
            player->att(Pl4s_VentCurLevel, cur_levelid + 1);
    }
    player->att(Pl4s_WeeklyCnt3Combat, player->att(Pl4s_WeeklyCnt3Combat) + 1);
}

void handle_cventurebosscombat(client_session_t* sess, cs::CMsg* msg) {
    auto player = sess->player;
    if (NULL == sess->player)
        return;

    int power = player->att(Pl4s_Power);
    if (power <= 0) {
        sess->send_notify("体力不足");
        return;
    }

    int32_t cur_levelid = player->att(Pl4s_VentCurLevel);
    int32_t bosslevel_id = msg->venturebosscombat().boss_levelid();
    const tagProtoBossLevel* bosslevel_proto = MAProto(BossLevel, bosslevel_id);
    if (NULL == bosslevel_proto) {
        sess->send_notify("boss关卡错误proto:%d", bosslevel_id);
        return;
    }

    player_t::boss_level_t* bosslevel = NULL;
    if (player->_boss_level_progress.count(bosslevel_id) == 0) {
        if (bosslevel_proto->prev_level >= cur_levelid) {
            sess->send_notify("先决关卡proto:%d", bosslevel_proto->prev_level);
            return;
        }
        bosslevel = new player_t::boss_level_t;
        bosslevel->id = bosslevel_id;
        bosslevel->cur_pass = 0;
        bosslevel->haspass = false;
        bosslevel->reset_count = 0;
        player->_boss_level_progress[bosslevel_id] = bosslevel;
        player->_boss_level_chg.insert(bosslevel_id);
    } else {
        bosslevel = player->_boss_level_progress[bosslevel_id];
    }

    if (bosslevel->cur_pass >= 3) {
        sess->send_notify("请刷新");
        return;
    }

    player->att(Pl4s_Power, power-1);

    CREATE_CS_SMSG(SCombat, combat);
    g_combatcookie(player.get(), NULL, 0);
    bool win = g_combat(player.get(), bosslevel_proto->boss[bosslevel->cur_pass], combat->mutable_combat());
    combat->set_levelid(bosslevel_id);
    sess->send_msg(___msg);

    if (win) {
        ++bosslevel->cur_pass;
        player->_boss_level_chg.insert(bosslevel_id);
        if (bosslevel->cur_pass >= 3)
            bosslevel->haspass = true;
    }
    player->att(Pl4s_WeeklyCnt3Combat, player->att(Pl4s_WeeklyCnt3Combat) + 1);
}

void handle_cventurebossreset(client_session_t* sess, cs::CMsg* msg) {
    auto player = sess->player;
    if (NULL == sess->player)
        return;

    int32_t vip_level = player->att(Pl4s_VipLevel);
    if (vip_level < 0 || vip_level > 4)
    	return;

    int32_t reset_num = player->att(Pl4s_VentureBossResetNum);
    if (reset_num >= g_game_cfg->VentureBossResetNum[vip_level]) {
        sess->send_notify("重置次数不够");
        return;
    }

    int32_t bosslevel_id = msg->venturebossreset().boss_levelid();
    if (player->_boss_level_progress.count(bosslevel_id) == 0) {
        sess->send_notify("无需重置");
        return;
    }
    player_t::boss_level_t* bosslevel = player->_boss_level_progress.get(bosslevel_id);
    if (NULL == bosslevel) {
        sess->send_notify("错误");
        return;
    }

    if (bosslevel->reset_count > 0) {
        sess->send_notify("今日已经重置过");
        return;
    }

    const tagProtoBossLevel* proto = MAProto(BossLevel, bosslevel_id);
    if (NULL == proto) {
        sess->send_notify("没有这个boss关卡");
        return;
    }

    if (reset_num > 0) {
        if (!player->can_consume(proto->reset_consume)) {
            sess->send_notify("消耗不足");
            return;
        }
    }

    bosslevel->cur_pass = 0;
    ++bosslevel->reset_count;
    player->_boss_level_chg.insert(bosslevel_id);

    if (reset_num > 0)
    	player->consume(proto->reset_consume);
    player->att(Pl4s_VentureBossResetNum, reset_num + 1);

}

void handle_cexploreenter(client_session_t* sess, cs::CMsg* msg) {
    auto player = sess->player;
    if (NULL == sess->player)
        return;

    // enter
    int32_t explid = player->att(Pl4s_ExplMap);
    int32_t toenter_explid = msg->exploreenter().explore_map();
    if (explid >= 0 && toenter_explid != explid) {
        sess->send_notify("请先完成之前的探险proto:%d", explid);
        return;
    }

    const tagProtoExplore* explore_proto = MAProto(Explore, toenter_explid);
    if (NULL == explore_proto) {
        sess->send_notify("无效探险proto:%d", toenter_explid);
        return;
    }

    auto bosslevel = player->_boss_level_progress.get(explore_proto->prev_bosslevel);
    if (NULL == bosslevel || !bosslevel->haspass) {
        sess->send_notify("请先完成boss关卡proto:%d", explore_proto->prev_bosslevel);
        return;
    }

    player->att(Pl4s_ExplMap, toenter_explid);

    // start
    if (explid < 0) {
        if (!player->can_consume(explore_proto->enter_consume)) {
            sess->send_notify("证书不够");
            return;
        }

        player->consume(explore_proto->enter_consume);

        int32_t actnum = explore_proto->init_actnum;

        // 便利物品，加行动点数
        for (int i=0; i<PlayerExplItemNum; ++i) {
            int32_t encounteritem_id = player->att(EPlAtt4Save(Pl4s_ExplItemBegin + i));
            const tagProtoEncounterItem* encounteritem_proto = MAProto(EncounterItem, encounteritem_id);
            if (NULL == encounteritem_proto)
                continue;

            actnum += encounteritem_proto->init_actnum_mod;
        }

        player->att(Pl4s_ExplActNo, actnum);
        player->att(Pl4s_ExplPos, 0);
        player->att(Pl4s_ExplSeed, rand());

        player->att(Pl4s_AliveCnt5Explore, player->att(Pl4s_AliveCnt5Explore) + 1);

        sess->stat.add_event(EET_Explore);
    }

}

void handle_cexplorebuyitem(client_session_t* sess, cs::CMsg* msg) {
    auto player = sess->player;
    if (NULL == sess->player)
        return;

    int32_t explid = player->att(Pl4s_ExplMap);
    if (explid >= 0) {
        sess->send_notify("已经开始，不能买东西了");
        return;
    }

    int32_t encounteritem_id = msg->explorebuyitem().encounteritem();
    const tagProtoEncounterItem* encounteritem_proto = MAProto(EncounterItem, encounteritem_id);
    if (NULL == encounteritem_proto) {
        sess->send_notify("无效物品proto:%d", encounteritem_id);
        return;
    }

    if (!player->can_consume(encounteritem_proto->consume)) {
        sess->send_notify("消耗不足");
        return;
    }

    EPlAtt4Save valid_slot = EPlAtt4Save(-1);
    for (int i=0; i< PlayerExplItemNum; ++i) {
        auto slot = EPlAtt4Save(Pl4s_ExplItemBegin + i);
        int32_t id = player->att(slot);
        if (id < 0 && valid_slot < 0)
            valid_slot = slot;

        if (id >= 0) {
            auto cur_proto = MAProto(EncounterItem, id);
            if (NULL == cur_proto) {
                sess->send_notify("无效物品proto:%d", id);
                return;
            }

            if (id == encounteritem_id || cur_proto->encounter == encounteritem_proto->encounter) {
                sess->send_notify("已经购买");
                return;
            }
        }
    }

    if (valid_slot < 0) {
        sess->send_notify("没有空位");
        return;
    }

    player->att(EPlAtt4Save(valid_slot), encounteritem_id);
    player->att(Pl4s_AliveCnt6ExplRent, player->att(Pl4s_AliveCnt6ExplRent) + 1);

    player->consume(encounteritem_proto->consume);

    sess->stat.add_consume_byid(ECT_VentureRent, -1, encounteritem_proto->consume);
}

void handle_cexploreact(client_session_t* sess, cs::CMsg* msg) {
    auto player = sess->player;
    if (NULL == sess->player)
        return;

    int32_t explid = player->att(Pl4s_ExplMap);
    if (explid < 0) {
        sess->send_notify("没有进入探险");
        return;
    }

    const tagProtoExplore* expl_proto = MAProto(Explore, explid);
    if (NULL == expl_proto) {
        sess->send_notify("无效探险proto:%d", explid);
        return;
    }

    int32_t explpos = player->att(Pl4s_ExplPos);
    if (explpos < 0) {
        sess->send_notify("还没开始，请开始");
        return;
    }

    int32_t actnum = player->att(Pl4s_ExplActNo);
    if (actnum <= 0) {
        sess->send_notify("已经输了");
        return;
    }

    int32_t explseed = player->att(Pl4s_ExplSeed);
    int64_t reward = -1;

    --actnum;
    ++explpos;

    // 遭遇
    int32_t encounter_id = random_item(explseed, explpos, expl_proto->encounter);
    const tagProtoEncounter* encounter_proto = MAProto(Encounter, encounter_id);
    if (NULL != encounter_proto) {
        int32_t actnum_mod = 0;

        for (int i=Pl4s_ExplItem1; i<=Pl4s_ExplItem4; ++i) {
            int32_t encounteritem_id = player->att(EPlAtt4Save(i));
            if (encounteritem_id < 0)
                continue;

            const tagProtoEncounterItem* encounteritem_proto = MAProto(EncounterItem, encounteritem_id);
            if (NULL == encounteritem_proto)
                continue;

            if (encounteritem_proto->encounter != encounter_id / 1000)
                continue;

            actnum_mod = encounteritem_proto->actnum_mod;
            break;
        }

        if (encounter_proto->boss >= 0) {
            CREATE_CS_SMSG(SCombat, combat);
            g_combatcookie(player.get(), NULL, 0);
            bool win = g_combat(player.get(), encounter_proto->boss, combat->mutable_combat());
            combat->set_levelid(explid);
            sess->send_msg(___msg);

            if (win)
                reward = encounter_proto->reward;
            else
                actnum += encounter_proto->actnum_mod;

        } else {
            if (encounter_proto->actnum_mod != 0)
                actnum += (encounter_proto->actnum_mod + actnum_mod);

            reward = encounter_proto->reward;
        }
    }

    if (explpos >= expl_proto->gridnum || actnum <= 0) {
        if (actnum >= 0) {
            CREATE_CS_SMSG(SReward, reward);
            player->reward(expl_proto->reward, reward->mutable_reward());
            reward->set_last(true);
            sess->send_msg(___msg);

            int32_t max_explid = max(player->att(Pl4s_MaxExplMap), expl_proto->id);
            player->att(Pl4s_MaxExplMap, max_explid);

            int mapcard_num = expl_proto->mapcard.size();
            if (mapcard_num > 0) {
                int32_t index = expl_proto->mapcard[rand()%mapcard_num];
                if (index >= 0 && !player->levelhas.test(index)) {
                    player->levelhas.set(index);
                    player->levelhas_added.push_back(index);
                }
            }
            player->att(Pl4s_WeeklyCnt4Explore, player->att(Pl4s_WeeklyCnt4Explore) + 1);
        }

        for (int i=0; i<PlayerExplItemNum; ++i)
            player->att(EPlAtt4Save(Pl4s_ExplItemBegin + i), -1);

        player->att(Pl4s_ExplMap, -1);
        player->att(Pl4s_ExplPos, explpos);
        player->att(Pl4s_ExplActNo, actnum);
    } else {
        player->att(Pl4s_ExplPos, explpos);
        player->att(Pl4s_ExplActNo, actnum);
        int rewardid = reward;
        if (rewardid >= 0) {
            CREATE_CS_SMSG(SReward, reward);
            player->reward(rewardid, reward->mutable_reward());
            sess->send_msg(___msg);
        }
    }
}

void handle_coccupationnum(client_session_t* sess, cs::CMsg* msg) {
	if (!g_console->_occupy_enabled) {
        sess->send_notify("占领模块临时关闭");
        return;
	}
    auto player = sess->player;
    if (NULL == player)
        return;

    int buynum = player->att(Pl4s_BuyOccupationNumNum);
    if (buynum >= 10) {
        sess->send_notify("次数超了");
        return;
    }

    if (!player->can_consume(g_game_cfg->BuyOccupationConsume)) {
        sess->send_notify("消耗不足");
        return;
    }

    int occupy_num = player->att(Pl4s_OccupyRemainNum);
    player->att(Pl4s_OccupyRemainNum, occupy_num+1);

    player->consume(g_game_cfg->BuyOccupationConsume);

    sess->stat.add_consume_byid(ECT_OccupationNum, -1, g_game_cfg->BuyOccupationConsume);
}


void handle_coccuptionstatus(client_session_t* sess, cs::CMsg* msg) {
	if (!g_console->_occupy_enabled) {
        //sess->send_notify("占领模块临时关闭");
		CREATE_CS_SMSG(SOccuptionStatus, occuptionstatus);
		sess->send_msg(___msg);
        return;
	}

    auto player = sess->player;
    if (NULL == player)
        return;

    vector<int32_t> levelids;
    auto status = msg->occuptionstatus();
    for (auto itr : status.levelid()) {
    	levelids.push_back(itr);
    }

    g_occupation->send_occuptionstatus(sess, levelids);
}

void handle_coccupy(client_session_t* sess, cs::CMsg* msg) {
	if (!g_console->_occupy_enabled) {
        sess->send_notify("占领模块临时关闭");
        CREATE_CS_SMSG(SOccupy, occupy);
        sess->send_msg(___msg);
        return;
	}

    auto player = sess->player;
    if (NULL == player)
        return;

    auto coccupy = msg->occupy();
    const tagProtoBossLevel* proto = MAProto(BossLevel, coccupy.levelid());
    if (NULL == proto)
        return;

    auto region = g_occupation->fetch_region(proto->id);
    if (NULL == region)
        return;

    int32_t occupyremainnum = player->att(Pl4s_OccupyRemainNum);
    if (occupyremainnum <= 0) {
        sess->send_notify("占领次数已到");
        return;
    }

    player->att(Pl4s_OccupyRemainNum, occupyremainnum - 1);

    CREATE_CS_SMSG(SOccupy, occupy);
    position_t &pos = region->pos;
    bool occupied = true;
    if (NULL != pos.occupant) {
    	g_combatcookie(player.get(), pos.occupant, 0);
        occupied = g_combat(player.get(), pos.occupant, occupy->mutable_combat());
        if (occupied) {
            // 删除旧的
            auto old_occupant = g_occupation->finish_occupy(pos.occupant->id, player->att(Plss_Name).c_str());
            safe_del(old_occupant);
        }
    }

    if (occupied) {
    	int32_t lastregion = -1;
        // 退出以前的占领
        player_t* cur_occupant = g_occupation->finish_occupy(player->id, NULL, &lastregion);
        if (NULL != cur_occupant) {
            safe_del(cur_occupant);
        }
        Json::Value json;
        player->save(json);
        cur_occupant = new player_t;
        if (!cur_occupant->init_image(json)) {
            safe_del(cur_occupant);
        }

        if (NULL != cur_occupant) {
            g_occupation->chged = true;
            pos.finish = g_clock->tt_now + proto->occupation_mins * 60;
            pos.occupant = cur_occupant;

            g_occupation->player_occupied[player->id] = region->proto->id;
            player->att(Pl4n_OccupiedMap, region->proto->id);

            // 占领状态
            vector<int32_t> levelids;
            levelids.push_back(coccupy.levelid());
            levelids.push_back(lastregion);
            g_occupation->send_occuptionstatus(sess, levelids);
        }
    }

    sess->send_msg(___msg);
}
